package com.baidu.iit.pvm.runtime;

import com.baidu.iit.pvm.PvmEventConstacts;
import com.baidu.iit.pvm.PvmException;
import com.baidu.iit.pvm.delegate.ExecutionListener;
import com.baidu.iit.pvm.process.ActivityImpl;
import com.baidu.iit.pvm.process.ScopeImpl;
import com.baidu.iit.pvm.process.TransitionImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * 选定路径后的操作，在节点或单元结束后执行
 * Created by 卫立 on 2014/4/7.
 *
 * @ThreadSafe
 */
public class AtomicOperationTransitionNotifyListenerTake implements AtomicOperation {

    private static Logger logger = LoggerFactory.getLogger(AtomicOperationTransitionNotifyListenerTake.class);


    public boolean isAsync(InterpretableExecution execution) {
        return false;
    }

    public void execute(InterpretableExecution execution) {

        //获取后续的执行路径
        TransitionImpl transition = execution.getTransition();

        List<ExecutionListener> executionListeners = transition.getExecutionListeners();

        //对监听信息进行遍历执行
        int executionListenerIndex = execution.getExecutionListenerIndex();
        if (executionListeners.size() > executionListenerIndex) {
            execution.setEventName(PvmEventConstacts.EVENTNAME_TAKE);
            execution.setEventSource(transition);
            ExecutionListener listener = executionListeners.get(executionListenerIndex);
            try {
                listener.notify(execution);
            } catch (RuntimeException e) {
                throw e;
            } catch (Exception e) {
                throw new PvmException("事件监听器不能执行 : " + e.getMessage(), e);
            }
            execution.setExecutionListenerIndex(executionListenerIndex + 1);
            execution.performOperation(this);

        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("{} takes transition {}", execution, transition);
            }
            execution.setExecutionListenerIndex(0);
            execution.setEventName(null);
            execution.setEventSource(null);

            ActivityImpl activity = (ActivityImpl) execution.getActivity();
            ActivityImpl nextScope = findNextScope(activity.getParent(), transition.getDestination());
            execution.setActivity(nextScope);
            execution.performOperation(TRANSITION_CREATE_SCOPE);
        }
    }

    /**
     * 查找下一个执行的节点
     * 当当前的目标节点不是下一个单元的根节点的时候往上寻找根节点作为目标节点
     *
     * @param outerScopeElement
     * @param destination
     * @return
     */
    public static ActivityImpl findNextScope(ScopeImpl outerScopeElement, ActivityImpl destination) {
        ActivityImpl nextScope = destination;

        //寻找节点的最上面的父节点作为 后续节点的起点
        while ((nextScope.getParent() instanceof ActivityImpl) && (nextScope.getParent() != outerScopeElement)) {
            nextScope = (ActivityImpl) nextScope.getParent();
        }
        return nextScope;
    }
}
